/**
 * @Copyright: 2010 杭州海康威视系统技术有限公司
 * @address: http://www.hikvision.com
 * @ProjectName: CMS基线平台
 * @Description: 公司内部的基础平台
 */
package com.hlkj.baojin.utils.hik;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;


/**
 * <p>
 * 处理HttpServletRequest对象工具类
 * </p>
 * @author chixueshun Jul 16, 2010 3:17:39 PM
 * @version V1.0
 */
@SuppressWarnings("unchecked")
public class RequestUtil {
	
	public static final String		ARRAY_PARAM_NAME_SEPARATOR	= "$_$";				// HttpServletRequest对象中数组参数名的分隔符，用于匹配特定的参数名
	public static final String		ARRAY_PARAM_VALUE_SEPARATOR	= "@_@";				// HttpServletRequest对象中数组参数值的分隔符，用于分隔参数值
	public static final String		MAP_PARAM_NAME_SEPARATOR	= "#_#";				// HttpServletRequest对象中Map参数名的分隔符，用于匹配特定的参数名
	public static final String		VALIDATOR_SEPARATOR			= "*_*";				// HttpServletRequest对象中Validator参数名的分隔符，用于匹配特定的参数名
	public static final String		VALIDATOR_NAME_SEPARATOR	= "!_!";				// HttpServletRequest对象中Validator参数名的分隔符，用于匹配特定的参数名
																						
	private static final Class<?>	CLAZZ						= RequestUtil.class;
	
	/**
	 * 转义SQL查询条件，将URL中的SQL查询条件转换为符合SQL规范的语句
	 * @author chixueshun Jul 16, 2010 3:17:51 PM
	 * @param condition SQL查询条件
	 * @return
	 */
	public static String parseSQLCondition(String condition) {
		condition = condition.replaceAll("@_@", " ");
		condition = condition.replaceAll("@eq@", "=");
		condition = condition.replaceAll("@lt@", "<");
		condition = condition.replaceAll("@le@", "<=");
		condition = condition.replaceAll("@gt@", ">");
		condition = condition.replaceAll("@ge@", ">=");
		condition = condition.replaceAll("@ne@", "!=");
		return condition;
	}
	
	
	public static String getRemortIP(HttpServletRequest request) {
		if (request.getHeader("x-forwarded-for") == null) {
			return request.getRemoteAddr();
		}
		return request.getHeader("x-forwarded-for");
	}
	
	/**
	 * 转义URL参数
	 * @author chixueshun Apr 11, 2011 4:38:11 PM
	 * @param param
	 * @return
	 */
	public static String decodeUrlParam(String param) {
		param = param.replaceAll("@and@", "&");
		param = param.replaceAll("@eq@", "=");
		param = param.replaceAll("@qm@", "?");
		param = param.replaceAll("@slash@", "/");
		param = param.replaceAll("@point@", ".");
		param = param.replaceAll("@exclamationMark@", "!");
		return param;
	}
	
	/**
	 * 根据请求填充数组
	 * @author chixueshun Jul 16, 2010 3:17:51 PM
	 * @param request 请求对象
	 * @param name Action中数组属性的名称
	 * @param clazz 数组属性的类型
	 * @return
	 */
	public static Object[] getArray(HttpServletRequest request, String name, Class<?> clazz) {
		Map<String, String[]> paramAndValues = new HashMap<String, String[]>();
		int size = setObjectArrayParam(request, name, paramAndValues);// 根据请求对象中的参数，匹配特定的参数名，将该名称与值填充到paramAndValues中
		Object[] object = null;
		try {
			object = createObject(paramAndValues, size, clazz);// 生成数组对象
		} catch (InstantiationException e) {
			LogUtil.logError(CLAZZ, e.getMessage());
		} catch (IllegalAccessException e) {
			LogUtil.logError(CLAZZ, e.getMessage());
		}
		return object;
	}
	
	public static Map<String, String> getMap(HttpServletRequest request, String name) {
		Map<String, String> paramAndValues = new HashMap<String, String>();
		int size = setObjectMapParam(request, name, paramAndValues);// 根据请求对象中的参数，匹配特定的参数名，将该名称与值填充到paramAndValues中
		return createMap(paramAndValues, size);
	}
	
	/**
	 * 根据请求填充列表
	 * @author chixueshun Jul 16, 2010 3:17:51 PM
	 * @param request 请求对象
	 * @param name Action中数组属性的名称
	 * @param clazz 数组属性的类型
	 * @return
	 */
	public static List<Object> getList(HttpServletRequest request, String name, Class<?> clazz) {
		Object[] object = getArray(request, name, clazz);
		if (object != null) {
			return Arrays.asList(object);
		}
		return null;
	}
	
	/**
	 * 根据请求对象、目标填充属性的名称填充参数-值列表
	 * @author chixueshun Jul 16, 2010 3:18:30 PM
	 * @param request 请求对象
	 * @param name 目标填充属性名称
	 * @param paramAndValues 待填充列表
	 * @return
	 */
	private static int setObjectArrayParam(HttpServletRequest request, String name, Map<String, String[]> paramAndValues) {
		int size = -1;
		for (Enumeration<String> parameterNames = request.getParameterNames(); parameterNames.hasMoreElements();) {
			String parameterName = parameterNames.nextElement();
			if (parameterName.startsWith(name + ARRAY_PARAM_NAME_SEPARATOR)) {// 匹配参数名为name+PARAM_NAME_SEPARATOR格式的参数
				String[] values = request.getParameterValues(parameterName);
				if (values != null && values.length > 0) {
					List<String> valueList = new ArrayList<String>();
					for (String value : values) {
						String[] v = value.split(ARRAY_PARAM_VALUE_SEPARATOR);// 将参数值以PARAM_VALUE_SEPARATOR分割
						valueList.addAll(Arrays.asList(v));
						
						if (size == -1) {
							size = value.replaceAll(ARRAY_PARAM_VALUE_SEPARATOR, ARRAY_PARAM_VALUE_SEPARATOR + "_").split(
									ARRAY_PARAM_VALUE_SEPARATOR).length;
						}
					}
					// 填充属性名-值表
					paramAndValues.put(parameterName.substring(name.length() + ARRAY_PARAM_NAME_SEPARATOR.length()),
							valueList.toArray(new String[valueList.size()]));
				}
			}
		}
		return size;
	}
	
	private static int setObjectMapParam(HttpServletRequest request, String name, Map<String, String> paramAndValues) {
		int size = -1;
		for (Enumeration<String> parameterNames = request.getParameterNames(); parameterNames.hasMoreElements();) {
			String parameterName = parameterNames.nextElement();
			if (parameterName.startsWith(name + MAP_PARAM_NAME_SEPARATOR)) {// 匹配参数名为name+PARAM_NAME_SEPARATOR格式的参数
				String[] values = request.getParameterValues(parameterName);
				if (values != null && values.length > 0) {
					String valueList = "";
					for (String value : values) {
						valueList += valueList.equals("")?value:"," + value;
					}
					// 填充属性名-值表
					paramAndValues.put(parameterName.substring(name.length() + MAP_PARAM_NAME_SEPARATOR.length()), valueList);
					size++;
				}
			}
		}
		return size;
	}
	
	/**
	 * 根据参数-值列表得到指定类型的对象数组
	 * @author chixueshun Jul 16, 2010 3:19:54 PM
	 * @param paramAndValues 参数-值列表
	 * @param size 数组大小
	 * @param clazz 填充对象类型
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private static Object[] createObject(final Map<String, String[]> paramAndValues, int size, Class<?> clazz)
			throws InstantiationException, IllegalAccessException {
		if (size < 0) {
			return new Object[0];
		}
		Object[] result = new Object[size];
		for (Entry<String, String[]> entry : paramAndValues.entrySet()) {// 遍历属性列表
			String[] values = entry.getValue();
			String field = entry.getKey();
			for (int i = 0; i < values.length; i++) {
				Object o = result[i];
				if (o == null) {
					o = clazz.newInstance();
				}
				setValue(o, field, values[i]);// 设置属性值
				result[i] = o;
			}
		}
		
		return result;
	}
	
	private static Map<String, String> createMap(final Map<String, String> paramAndValues, int size) {
		if (size < 0) {
			return null;
		}
		Map<String, String> result = new HashMap<String, String>();
		for (Entry<String, String> entry : paramAndValues.entrySet()) {// 遍历属性列表
			result.put(entry.getKey(), entry.getValue());
		}
		
		return result;
	}
	
	/**
	 * 对指定对象设置指定属性名的值
	 * @author chixueshun Jul 16, 2010 3:21:17 PM
	 * @param object 指定对象
	 * @param name 指定属性名
	 * @param value 属性值
	 */
	private static void setValue(Object object, String name, String value) {
		try {
			Class<? extends Object> clazz = object.getClass();
			if (Map.class.isAssignableFrom(clazz)) {
				((Map)object).put(name, value);
			} else {
				int index = name.indexOf(".");
				if (index != -1) {// 判断是否是复合对象的属性
					String subName = name.substring(0, index);// 获得复合对象属性名
					Field subField = clazz.getDeclaredField(subName);
					Class<?> subFieldType = subField.getType();
					if (subField != null) {
						String methodPostfix = subName.substring(0, 1).toUpperCase(Locale.getDefault())
								+ subName.substring(1, subName.length());
						String methodName = "get" + methodPostfix;// 得到属性的get方法名
						Method method = clazz.getMethod(methodName);// 得到属性的set方法对象
						if (method != null) {
							Object subObject = method.invoke(object);// 执行set方法
							if (subObject == null) {
								if (subFieldType == Map.class || Map.class.isAssignableFrom(subFieldType)) {
									subObject = new HashMap();
								} else {
									subObject = subFieldType.newInstance();
								}
							}
							setValue(subObject, name.substring(index + 1, name.length()), value);
							
							methodName = "set" + methodPostfix;// 得到属性的get方法名
							method = clazz.getMethod(methodName, subFieldType);// 得到属性的set方法对象
							if (method != null) {
								method.invoke(object, subObject);
							}
						}
					}
				} else {
					Field field = null;
					try {
						field = clazz.getDeclaredField(name);
						boolean isFoolback = false;// 用于判断属性原来的可访问性
						Object v = null;
						if (field.isAccessible() == false) {
							isFoolback = true;// 若属性原来不可访问，则标记为false，之后将可访问性回置
							field.setAccessible(true);// 将可访问性置成true
						}
						Class<?> fieldType = field.getType();// 得到属性类型
						if (value == null) {
							v = value;
						} else
							if (fieldType == int.class || fieldType == Integer.class) {
								v = Integer.parseInt(value);
							} else
								if (fieldType == long.class || fieldType == Long.class) {
									v = Long.parseLong(value);
								} else
									if (fieldType == float.class || fieldType == Float.class) {
										v = Float.parseFloat(value);
									} else
										if (fieldType == double.class || fieldType == Double.class) {
											v = Double.parseDouble(value);
										} else
											if (fieldType == short.class || fieldType == Short.class) {
												v = Short.parseShort(value);
											} else
												if (fieldType == byte.class || fieldType == Byte.class) {
													v = Byte.parseByte(value);
												} else
													if (fieldType == boolean.class || fieldType == Boolean.class) {
														v = Boolean.parseBoolean(value);
													} else {
														v = value;// String
													}
						if (isFoolback) {
							field.setAccessible(false);
						}
						String methodName = "set" + name.substring(0, 1).toUpperCase(Locale.getDefault())
								+ name.substring(1, name.length());// 得到属性的set方法名
						Method method = clazz.getMethod(methodName, fieldType);// 得到属性的set方法对象
						if (method != null) {
							method.invoke(object, v);// 执行set方法
						}
					} catch (NoSuchFieldException nse) {
						// 若没有对应属性，则尝试找到方法签名为：set(String name,Object value)的方式进行设值
						Method method = clazz.getDeclaredMethod("set", String.class, Object.class);
						if (method != null) {
							method.invoke(object, name, value);
						} else {
							throw nse;
						}
					}
				}
			}
		} catch (NoSuchMethodException e) {
			LogUtil.logError(RequestUtil.class, e);
		} catch (InstantiationException e) {
			LogUtil.logError(RequestUtil.class, e);
		} catch (NoSuchFieldException e) {
			LogUtil.logError(RequestUtil.class, e);
		} catch (IllegalAccessException e) {
			LogUtil.logError(RequestUtil.class, e);
		} catch (InvocationTargetException e) {
			LogUtil.logError(RequestUtil.class, e);
		}
	}
	
	public static String getCookieValue(HttpServletRequest request, String name) {
		String value = "";
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if (name.equalsIgnoreCase(cookie.getName())) {
					value = cookie.getValue();
				}
			}
		}
		return value;
	}
	
	/**
	 * 解析验证规则并校验
	 * @author chixueshun 2013-12-18 上午11:07:00
	 * @param request
	 * @return
	 */
	public static String doValidate(String value, String validator) {
		
		String[] rules = validator.split(";");
		Map<String, String> ruleMap = new HashMap<String, String>();
		for (String rule : rules) {
			rule = (rule == null)?"":rule.trim();
			if ("".equals(rule)) {
				continue;
			}
			String[] ruleItems = rule.split(":");
			String k = ruleItems[0];
			String v = ruleItems.length > 1?ruleItems[1]:"";
			ruleMap.put(k, v);
		}
		if (ruleMap.isEmpty()) {
			return "";
		}
		String length = StringUtils.safeNullValue(ruleMap.get("length"));
		String domain = StringUtils.safeNullValue(ruleMap.get("domain"));// 区域，如1~7，参考接口说明
		// 验证must
		if (ruleMap.containsKey("must")) {
			if (value == null || value.length() == 0) {
				return "此项为必填项";
			}
		}
		// 验证length
		if (!length.equals("")) {
			try {
				int stringLength = value.length();
				if (length.indexOf("~") == -1) {
					if (stringLength != Integer.parseInt(length)) {
						return "请输入长度为 " + length + " 的字符！";
					}
				} else {
					String[] ls = length.split("~");
					if (stringLength < Integer.parseInt(ls[0]) || stringLength > Integer.parseInt(ls[1])) {
						return "请输入长度为 " + length + " 的字符！";
					}
				}
			} catch (Exception e) {
			}
		}
		// 验证size
		String size = StringUtils.safeNullValue(ruleMap.get("size"));
		if (!size.equals("")) {
			try {
				String[] ls = size.split("~");
				int stringLength = value.length();
				if (stringLength < Integer.parseInt(ls[0]) || stringLength > Integer.parseInt(ls[1])) {
					return "请输入长度为 " + size + " 的字符！";
				}
			} catch (Exception e) {
			}
		}
		
		// 验证size
		String byteLength = StringUtils.safeNullValue(ruleMap.get("byteLength"));
		if (!byteLength.equals("")) {
			try {
				String[] ls = byteLength.split("~");
				int stringLength = value.getBytes().length;
				if (stringLength < Integer.parseInt(ls[0]) || stringLength > Integer.parseInt(ls[1])) {
					return "请输入长度为 " + byteLength + " 的字符！";
				}
			} catch (Exception e) {
			}
		}
		if (!ObjectUtils.isStringEmpty(value)) {
			// 验证实数
			if (ruleMap.containsKey("number")) {
				try {
					double d = Double.parseDouble(value);
					if (!"".equals(domain)) {
						String[] ds = domain.split("~");
						if (d < Double.parseDouble(ds[0]) || d > Double.parseDouble(ds[1])) {
							return "请输入大小为 " + domain + " 的数值！";
						}
					}
				} catch (Exception e) {
					return "请输入正确的数字！";
				}
			}
			// 验证ip
			if (ruleMap.containsKey("ip")) {
				if (!FieldValidator.isIPAddress(value)) {
					return "请输入有效的IP地址！";
				}
			}
			// 验证整型
			if (ruleMap.containsKey("subNetMask")) {
				if (!FieldValidator.isSubNetMask(value)) {
					return "请输入有效的子网掩码！";
				}
				
			}
			// 验证整型
			if (ruleMap.containsKey("integer")) {
				try {
					double i = Integer.parseInt(value);
					if (!"".equals(domain)) {
						String[] is = domain.split("~");
						if (i < Long.parseLong(is[0]) || i > Long.parseLong(is[1])) {
							return "请输入大小为 " + domain + " 的整数！";
						}
					}
				} catch (Exception e) {
					return "请输入正确的整数！";
				}
			}
			// 验证整型字符
			if (ruleMap.containsKey("integers")) {
				try {
					for (int i = 1; i <= value.length(); i++) {
						Integer.parseInt(value.substring(i - 1, i));
					}
				} catch (Exception e) {
					return "请输入正确的整型字符！";
				}
			}
			// 日期
			if (ruleMap.containsKey("date")) {
				String formatStr = ruleMap.get("date");
				formatStr = (formatStr == null)?"":formatStr.trim();
				if (formatStr.equals("")) {
					formatStr = "yyyy-MM-dd HH:mm:ss";
				}
				try {
					DateFormat format = new SimpleDateFormat(formatStr);
					format.parse(value);
				} catch (Exception e) {
					return "请输入格式为(" + formatStr + ")的日期";
				}
			}
			// 验证非法字符
			if (ruleMap.containsKey("illegalchar")) {
				String[] illegalchars = new String[] {"￥", "$", "%", "&", "\\", "<", ">", "\'", "\"", "^", "@", "?", "/", "[", "]", "`",
						";", "’", "*", ",", "null"};
				if (value.trim().toLowerCase(Locale.getDefault()).equals("null")) {
					return "输入不能为" + value;
				}
				for (int i = 1; i <= value.length(); i++) {
					String subStr = value.substring(i - 1, i);
					for (int j = 0; j < illegalchars.length; j++) {
						if (subStr.equals(illegalchars[j])) {
							return "不能包含非法字符：" + illegalchars[j];
						}
					}
				}
			}
			// 验证email
			if (ruleMap.containsKey("email")) {
				if (!FieldValidator.isEmail(value)) {
					return "请输入有效的E-Mail地址！";
				}
			}
			// 验证手机号码
			if (ruleMap.containsKey("mobilePhone") || ruleMap.containsKey("phone")) {
				if (!FieldValidator.isMobilePhone(value)) {
					return "请输入有效的手机号码！";
				}
			}
			
		}
		return "";
		
	}
}
